要注意所使用的实战两个摄像头必须经过章节2的摄像头校正,在本文中,制作低因此,成本全顺电动门至于更详细的立体双目视觉系统搭建可以看看文章一起搭建双目视觉系统。以简化点对应搜索。相机立体校正运用旋转使两个相机图像面都在同一平面上,实战具体来说包括立体相机的制作低创建,左图是成本原图,你会发现手机的立体相对水平位置是不同的。Emat和Fmat。相机已经非常成熟了,实战必须了解3D眼镜的制作低工作原理。函数介绍见javascript:void(0) cv::stereoRectify(new_mtxL,成本 distL, new_mtxR, distR, grayR.size(), Rot, Trns, rect_l, rect_r, proj_mat_l, proj_mat_r, Q, 1); Python 由于我们假设摄像机是固定的,主要是立体下载速度快): OpenCV-Practical-Exercise-gitee 我们通常都使用下图所示的红青色3D眼镜来体验3D效果。我们将所有连续的相机立体图像保存为视频,说白了这里你需要一个自己的立体相机(双目立体相机),因此,就是带两个摄像头的那种(目就是指眼睛,如下图所示,T_L和T_R为位移向量 cv::Mat mtxL, distL, R_L, T_L; cv::Mat mtxR, distR, R_R, T_R; cv::Mat new_mtxL, new_mtxR; // Calibrating left camera // 校正左边相机 // 相机标定函数 // 函数使823569 cv::calibrateCamera(objpoints, imgpointsL, grayL.size(), mtxL, distL, R_L, T_L); // 去畸变, 我们了解了当使用立体3D眼镜观看时, 生成的视差图如下图所示: 我们观察到,因此,这就是我们制作3D视频的方式!下图就是zed系列某部立体相机的真容,关于立体相机的原理见 深度相机原理揭秘–双目立体视觉 。专门的工业级双目立体相机价格大概5000多左右,会提供图像,我们学习如何创建自己的立体相机,我们观察到,看看就好2.2.4 获得未失真的校正立体图像对所需的映射
1 相关介绍
1.1 背景
3.2 创建自定义3D视频
如果是自己弄台双目立体相机,本文主要说的是低成本,
为了理解立体标定的重要性,那么我们的左眼和右眼捕获的信息之间有什么区别?
例如将你的手机放在你的面前正中处,而是在软件方面体标定并校正摄像机。我们可以使用立体相机设置来捕获多张相机图像,然后生成视差图。你可以看用文章DIY 3D立体相机的帖子整理用摄像头来自己搭建双目立体相机。如下图所示,确定两个摄像机之间的转换关系。这种位置差异称为水平视差。将此映射应用于原始图像,你可以买,用于计算相机间的转换关系。我们提供了没有立体标定的图像,反正最终弄出来的结果如下图所示:如果是高精度双目视觉应用的话,它越近。具体原理见双目立体标定。使用未校准的立体相机设置生成的视差图非常嘈杂且不准确。本文只是简单的讲一讲相关原理, 这一些步骤就是相机标定中的张正友标定法,或者也可以通过两部手机搭建双目立体相机,物体的视差越高,为什么还要分别标定相机呢? 这是因为由于要计算的参数很多(较大的参数空间),我们如何体验3D效果?这些是使用立体摄像机设置捕获的。但是,具体见Projection Matrices。你需要进行立体标定(stereo calibration)以搭建自己的视觉系统,所以本文看看就好。所以我们可以用另外一种方式,不是随便就能弄好的,另外双目视觉加上深度学习还蛮好水论文的。但是,双目就是两只眼睛),详细使用见双目视觉之空间坐标计算。为什么要这要做后面会说到。然后进行相机校正。我们了解了立体相机以及如何将其用于帮助计算机感知深度。 仅当摄像机平行时才可能出现上图这种情况。我们就可以创建3D视频了。主要是讲立体相机的校准。这种双目摄像机模仿人的视觉,这是我们如何使用我们的双眼视觉系统来感知深度的原因。立体相机的校准以及自定义3D视频, cv::Mat Rot, Trns, Emat, Fmat; int flag = 0; flag |= cv::CALIB_FIX_INTRINSIC; // This step is performed to transformation between the two cameras and calculate Essential and Fundamenatl matrix // 同时标定两个摄像头,如下图所示,人们是通过使用红色和青色的滤镜对每只眼睛的图像进行编码来实现的。这增加了迭代方法偏离正确解决方案的机会。因此, 本文主要参考 Making A Low-Cost Stereo Camera Using OpenCV和 双目视觉之空间坐标计算。并了解如何将其用于创建3D视频。无需物理调整摄像机,总体相机立体标定过程由图表示如下所示: 以下几节具体步骤可以跳过不看,与前一张相比,则success=true // 具体函数使488 successL = cv::findChessboardCorners( grayL, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_ptsL); // cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE); successR = cv::findChessboardCorners( grayR, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_ptsR); // cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FAST_CHECK | cv::CALIB_CB_NORMALIZE_IMAGE); // 如果检测到所需的角点个数,然后去除畸形点,在我们了解如何制作3D视频之前,他们使用了红青色3D眼镜,也可以自己创造一个。但是实际过程中,实际上没人这样干, 您现在观察到了哪些变化?与对象相对应的水平视差增加。工业级标准立体摄像机设置使用一对相同的摄像机。所以应用很广泛(主要是工业机器人视觉)。我们会对两个相机分别进行标定。并且在诸如角点检测和近似点之类的步骤中累积了错误。比如特斯拉、因此,然后,以及使用这些图像生成的视差图。并为每个相机图像对创建一个立体图像。毕竟工业级双目相机的搭建技术含量很高,我们就可以进行立体校正 // stereoRectify同时校正两个摄像机,并仅使用stereoCalibrate()方法来查找立体相机之间的对应关系。stereolabs家的zed系列相机,我们计算将立体图像对转换为未失真的校正立体图像对的映射,这创造了深度的幻觉。双目摄像机也广泛应用于无人驾驶,国内在这一块相对比较薄弱。使用OpenCV的initUndistortRectifyMap方法找到未失真和已校正图像对所需的映射。将手机靠近您并重复相同的实验。 本文主要讲述利用OpenCV制作低成本立体相机以及如何使用OpenCV创建3D视频,有些双目立体摄像机还自带深度学习算法,下图说明了立体标定与校准的过程。这样可以确保相应的点具有相同的Y坐标, C++ Python 校准完我们的DIY立体相机后,这些图像被称为立体影片, 下图显示了相应的关键点具有相等的Y坐标的立体图像,百度的图片。cornerSubPix用于亚像素角点检测 // 具体参 cv::cornerSubPix(grayL, corner_ptsL, cv::Size(11, 11), cv::Size(-1, -1), criteria); cv::cornerSubPix(grayR, corner_ptsR, cv::Size(11, 11), cv::Size(-1, -1), criteria); // Displaying the detected corner points on the checker board // drawChessboardCorners用于绘制棋盘格角点的函数 cv::drawChessboardCorners(frameL, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_ptsL, successL); cv::drawChessboardCorners(frameR, cv::Size(CHECKERBOARD[0], CHECKERBOARD[1]), corner_ptsR, successR); // 保存数据以供后续使用 // 保存三维点数据 objpoints.push_back(objp); // 保存角点信息 imgpointsL.push_back(corner_ptsL); imgpointsR.push_back(corner_ptsR); } //cv::imshow("ImageL", frameL); //cv::imshow("ImageR", frameR); //cv::waitKey(0); } // 关闭所有窗口 cv::destroyAllWindows(); // 通过传递已知三维点(objpoints)的值和检测到的角点(imgpoints)的相应像素坐标来执行相机校准 // mtxL,mtxR为内参数矩阵,因此内在参数是相同的。 当你有了立体相机,但是原理大差不差。 在[OpenCV实战]49 对极几何与立体视觉初探文章中,闭上左眼只用右眼观察手机和闭上右眼只用左眼观察手机,最初,它们捕获的信息不同。它是如何工作的?当屏幕只是平面时, 整个过程如下所示: 代码如下: C++ Python文章目录
1 相关介绍1.1 背景1.2 创建双目立体相机2 相机立体标定与校正2.1 立体标定重要性2.2 相机立体标定和校正的步骤2.2.1 单个相机校正2.2.2 使用固定的固有参数执行立体标定2.2.3 立体校正2.2.4 获得未失真的校正立体图像对所需的映射3 自定义3D视频3.1 3D眼镜如何工作?3.2 创建自定义3D视频4 参考3 自定义3D视频
3.1 3D眼镜如何工作?
2.2 相机立体标定和校正的步骤
4 参考
Making A Low-Cost Stereo Camera Using OpenCV[OpenCV实战]49 对极几何与立体视觉初探3D Camera Survey深度相机原理揭秘–双目立体视觉 DIY 3D立体相机的帖子整理低成本DIY拍摄3D照片的相机如何用两台傻瓜相机制作自己的3D相机zed系列相机一起搭建双目视觉系统双目立体标定双目视觉之空间坐标计算相机标定之张正友标定法数学原理详解Projection Matrices
如果OpenCV的stereoCalibrate()方法可以对两个相机中的每一个进行校正,有专门的双目立体相机,图森未来,也不是不行。
代码如下,主要讲的是提取角点,cv::Point3f(j, i, 0)保存的是x,y,z坐标。
所谓角点检测如下图所示,这一步可选 // getOptimalNewCameraMatrix函数使用见https://www.jianshu.com/p/df78749b4318 new_mtxL = cv::getOptimalNewCameraMatrix(mtxL, distL, grayL.size(), 1, grayL.size(), 0); // Calibrating right camera // 校正右边相机 cv::calibrateCamera(objpoints, imgpointsR, grayR.size(), mtxR, distR, R_R, T_R); new_mtxR = cv::getOptimalNewCameraMatrix(mtxR, distR, grayR.size(), 1, grayR.size(), 0);
Python
# Set the path to the images captured by the left and right cameras pathL = "./data/stereoL/" pathR = "./data/stereoR/" print("Extracting image coordinates of respective 3D pattern ....\n") # Termination criteria for refining the detected corners # 细化检测角点的终止准则 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp = np.zeros((9 * 6, 3), np.float32) objp[:, :2] = np.mgrid[0:9, 0:6].T.reshape(-1, 2) img_ptsL = [] img_ptsR = [] obj_pts = [] # 处理每一张图 for i in tqdm(range(1, 28)): imgL = cv2.imread(pathL + "img%d.png" % i) imgR = cv2.imread(pathR + "img%d.png" % i) imgL_gray = cv2.imread(pathL + "img%d.png" % i, 0) imgR_gray = cv2.imread(pathR + "img%d.png" % i, 0) outputL = imgL.copy() outputR = imgR.copy() retR, cornersR = cv2.findChessboardCorners(outputR, (9, 6), None) retL, cornersL = cv2.findChessboardCorners(outputL, (9, 6), None) if retR and retL: obj_pts.append(objp) cv2.cornerSubPix(imgR_gray, cornersR, (11, 11), (-1, -1), criteria) cv2.cornerSubPix(imgL_gray, cornersL, (11, 11), (-1, -1), criteria) cv2.drawChessboardCorners(outputR, (9, 6), cornersR, retR) cv2.drawChessboardCorners(outputL, (9, 6), cornersL, retL) # cv2.imshow(cornersR,outputR) # cv2.imshow(cornersL,outputL) # cv2.waitKey(0) img_ptsL.append(cornersL) img_ptsR.append(cornersR) print("Calculating left camera parameters ... ") # Calibrating left camera # 校正左边相机 retL, mtxL, distL, rvecsL, tvecsL = cv2.calibrateCamera(obj_pts, img_ptsL, imgL_gray.shape[::-1], None, None) hL, wL = imgL_gray.shape[:2] new_mtxL, roiL = cv2.getOptimalNewCameraMatrix(mtxL, distL, (wL, hL), 1, (wL, hL)) print("Calculating right camera parameters ... ") # Calibrating right camera # 校正右边相机 retR, mtxR, distR, rvecsR, tvecsR = cv2.calibrateCamera(obj_pts, img_ptsR, imgR_gray.shape[::-1], None, None) hR, wR = imgR_gray.shape[:2] new_mtxR, roiR = cv2.getOptimalNewCameraMatrix(mtxR, distR, (wR, hR), 1, (wR, hR))校准摄像机后,以便只计算Rot、这样实现了立体标定,代码如下:
C++
cv::Mat rect_l, rect_r, proj_mat_l, proj_mat_r, Q; // Once we know the transformation between the two cameras we can perform stereo rectification // 一旦我们知道两个摄像机之间的变换,现在的视差图噪声更低。应用于两个图像的变换以进行立体校正。优化相机内参,4000多一点,我们可以通过使用称为体视学stereoscopy的方法, for (int i{ 0 }; i < CHECKERBOARD[1]; i++) { for (int j{ 0 }; j < CHECKERBOARD[0]; j++) { objp.push_back(cv::Point3f(j, i, 0)); } } // Extracting path of individual image stored in a given directory // 提取存储在给定目录中的单个图像的路径 std::vector<cv::String> imagesL, imagesR; // Path of the folder containing checkerboard images // 包含棋盘图像的文件夹的路径 // pathL和pathR分别为两个摄像头在多个时刻拍摄的图像 std::string pathL = "./data/stereoL/*.png"; std::string pathR = "./data/stereoR/*.png"; // 提取两个文件夹 所有的图像 cv::glob(pathL, imagesL); cv::glob(pathR, imagesR); cv::Mat frameL, frameR, grayL, grayR; // vector to store the pixel coordinates of detected checker board corners // 用于存储检测到的棋盘角点的像素坐标的向量 std::vector<cv::Point2f> corner_ptsL, corner_ptsR; bool successL, successR; // Looping over all the images in the directory // 遍历目录中的所有图像 for (int i{ 0 }; i < imagesL.size(); i++) { // 提取同一时刻分别用两个摄像头拍到的照片 frameL = cv::imread(imagesL[i]); cv::cvtColor(frameL, grayL, cv::COLOR_BGR2GRAY); frameR = cv::imread(imagesR[i]); cv::cvtColor(frameR, grayR, cv::COLOR_BGR2GRAY); // Finding checker board corners // 寻找棋盘图的内角点位置 // If desired number of corners are found in the image then success = true // 如果在图像中找到所需的角数,现在,家用的或者用来玩的最低1000能买到,以校正未失真图像。关于立体相机型号可以看看3D Camera Survey。我们使用双目视觉系统感知世界。 distL和distR为畸变矩阵 // R_L和R_R为旋转向量,但是保持两个摄像机严格固定和平行。立体摄像头设置通常包含两个相同的摄像头,自己也不需要有双目相机,则细化像素坐标并将其显示在棋盘格图像上 if ((successL) && (successR)) { // TermCriteria定义迭代算法终止条件的类 // 具体使用见 https://www.jianshu.com/p/548868c4d34e cv::TermCriteria criteria(cv::TermCriteria::EPS | cv::TermCriteria::MAX_ITER, 30, 0.001); // refining pixel coordinates for given 2d points. // 细化给定2D点的像素坐标,代码如下:
C++
// Here we fix the intrinsic camara matrixes so that only Rot, Trns, Emat and Fmat // are calculated. Hence intrinsic parameters are the same. // 在这里,我们观察到这些线不是完全水平的。使用前面步骤中获得的参数和OpenCV的stereoCalibrate方法,直接看代码calibrate.cpp/calibrate.py!在执行立体标定之前,就能够进行立体校正。只要有这个东西就好了。因此无需再次计算变换。这些东西不是一句两句就能说清楚,反正很多人也这样干。小鹏汽车在自家的无人驾驶汽车上都安载了立体相机,对于3D电影,我们通常说立体相机一般是指双目立体相机,我们修正了固有的camara矩阵,准确来说是模仿双目立体相机,它们以固定的距离隔开。右图是角点检测的可视化结果,我们所需要提取就是角点,我们还传递两个相机捕获的3D点和相应的2D像素坐标,详情见低成本DIY拍摄3D照片的相机和如何用两台傻瓜相机制作自己的3D相机。我们分别计算摄像机参数,并将其存储以备将来使用。stereoRectify方法还能返回新坐标空间中的投影矩阵。
C++
// Creating vector to store vectors of 3D points for each checkerboard image // 创建vector以存储每个棋盘图像的3D点矢量 std::vector<std::vector<cv::Point3f> > objpoints; // Creating vector to store vectors of 2D points for each checkerboard image // 创建vector以存储每个棋盘图像的2D点矢量 std::vector<std::vector<cv::Point2f> > imgpointsL, imgpointsR; // Defining the world coordinates for 3D points // 定义三维点的世界坐标 std::vector<cv::Point3f> objp; // 初始化点,和转换关系参数,双目和多目的都有。用这种方法产生的立体效果称为立体3D。为什么会这样?根据[OpenCV实战]49 对极几何与立体视觉初探里提到的,Trns、这里面会涉及到一系列的OpenCV函数,立体图像对如何转换为立体3D图像以产生深度的幻觉。数学原理详解相机标定之张正友标定法数学原理详解。并且眼镜被称为立体3D眼镜。本文所有代码见:
github: OpenCV-Practical-Exercisegitee(备份,或者我们想要达到基本平行需要耗费大量的时间来调整摄像机。函数介绍见javascript:void(0) cv::stereoCalibrate(objpoints, imgpointsL, imgpointsR, new_mtxL, distL, new_mtxR, distR, grayR.size(), Rot, Trns, Emat, Fmat, flag, cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 30, 1e-6));Python
print("Stereo calibration .....") flags = 0 flags |= cv2.CALIB_FIX_INTRINSIC # Here we fix the intrinsic camara matrixes so that only Rot, Trns, Emat and Fmat are calculated. # Hence intrinsic parameters are the same criteria_stereo = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 立体标定 # This step is performed to transformation between the two cameras and calculate Essential and Fundamenatl matrix retS, new_mtxL, distL, new_mtxR, distR, Rot, Trns, Emat, Fmat = cv2.stereoCalibrate(obj_pts, img_ptsL, img_ptsR, new_mtxL, distL, new_mtxR, distR, imgL_gray.shape[::-1], criteria_stereo, flags)使用相机间的内外参数,关于投影矩阵这是个相机几何学的基础概念,这个想法是在平行于穿过光学中心的线的公共平面上重新投影两个图像。分别向每只眼睛人工呈现两个不同的图像来模拟这种视。